﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DO.Domain;
using DO.Domain.Repositories;
//
using DO.Domain.Entities;
using System.Reflection;

namespace DO.Naive.Repositories
{
    #region Refactored

    public class RepositoryEntityStore<TEntity> : IRepository<TEntity>
    {
        protected readonly IDictionary<long, TEntity> RepositoryMap = new Dictionary<long, TEntity>();

        #region IRepository<TEntity> Members

        public TEntity Save(TEntity instance)
        {
            IEntity entityInstance = GetEntityInstance(instance);
            if (entityInstance.Identity!= 0)
            {
                throw new ApplicationException("Entity instance cannot be saved, the field Id was not cero");
            }
            GetNewId(instance);
            RepositoryMap.Add(entityInstance.Identity, instance);
            return instance;
        }

        public void Update(TEntity instance)
        {
            IEntity entityInstance = GetEntityInstance(instance);
            if (entityInstance.Identity == 0)
            {
                throw new ApplicationException("Entity instance cannot be updated, the Id field was cero");
            }
            this.RepositoryMap[entityInstance.Identity] = instance;
        }

        public void Delete(TEntity instance)
        {
            IEntity entityInstance = GetEntityInstance(instance);
            RepositoryMap.Remove(entityInstance.Identity);
        }

        public TEntity GetByIdentity(long identity)
        {
            return RepositoryMap[identity];
        }

        public IQueryable<TEntity> FindAll()
        {
            return RepositoryMap.Values.AsQueryable();
        }

        #endregion


        #region Helper Methods
        private void GetNewId(TEntity instance)
        {
            GetEntityInstance(instance);
            long max = 0;

            if (RepositoryMap.Count > 0)
            {
                max = RepositoryMap.Keys.Max();
            }
            max = ++max;

            var setter = GetSetter(instance.GetType());

            setter.Invoke(instance, new object[] { max });
        }

        private readonly IDictionary<Type, MethodInfo> Setters = new Dictionary<Type, MethodInfo>();

        private MethodInfo GetSetter(Type type)
        {
            if(this.Setters.ContainsKey(type))
            {
                return Setters[type];
            }

            var setter = type.GetProperty("Id").GetSetMethod(true);
            Setters.Add(type, setter);

            return setter;
        }

        private IEntity GetEntityInstance(TEntity instace)
        {
            var entityInstance = instace as IEntity;
            
            if(entityInstance == null)
            {
                throw new ArgumentException("Passed instance is not an IEntity");
            }

            return entityInstance;
        }

        #endregion
    }
    #endregion Refactored
 
}
